textiter: fix bug in case insensitive backward search
authorSébastien Wilmet <swilmet@gnome.org>
Thu, 26 Nov 2015 12:31:19 +0000 (13:31 +0100)
committerSébastien Wilmet <swilmet@gnome.org>
Mon, 30 Nov 2015 18:46:16 +0000 (19:46 +0100)
'win.lines' contains the same content as the GtkTextBuffer, so to find
@match_start, forward_chars_with_skipping() is called with
skip_decomp=FALSE (the last parameter). So far so good.

On the other hand, the content 'lines' (the needle split in lines) is
casefolded and normalized for a case insensitive search. So,
forward_chars_with_skipping(..., skip_decomp=TRUE) must be called only
for the portion of text containing the needle.

Since 'start_tmp' contains the location at the start of the match, we
can simply begin at that location to find the end of the match.

Unit tests are added.

https://bugzilla.gnome.org/show_bug.cgi?id=758698

gtk/gtktextiter.c
testsuite/gtk/textiter.c

index a863c3868279be02523f66633ae698e4eff74e0a..2496ea85bc536fbb568bebf010f0fd12e72f3819 100644 (file)
@@ -5309,37 +5309,34 @@ gtk_text_iter_backward_search (const GtkTextIter *iter,
         {
           /* Match! */
           gint offset;
-          GtkTextIter next;
           GtkTextIter start_tmp;
-          
+          GtkTextIter end_tmp;
+
           /* Offset to start of search string */
           offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
 
-          next = win.first_line_start;
-          start_tmp = next;
+          start_tmp = win.first_line_start;
           forward_chars_with_skipping (&start_tmp, offset,
                                        visible_only, !slice, FALSE);
 
           if (limit &&
               gtk_text_iter_compare (limit, &start_tmp) > 0)
             goto out; /* match was bogus */
-          
+
           if (match_start)
             *match_start = start_tmp;
 
           /* Go to end of search string */
-          l = lines;
-          while (*l)
-            {
-              offset += g_utf8_strlen (*l, -1);
-              ++l;
-            }
+          offset = 0;
+          for (l = lines; *l != NULL; l++)
+            offset += g_utf8_strlen (*l, -1);
 
-          forward_chars_with_skipping (&next, offset,
+          end_tmp = start_tmp;
+          forward_chars_with_skipping (&end_tmp, offset,
                                        visible_only, !slice, case_insensitive);
 
           if (match_end)
-            *match_end = next;
+            *match_end = end_tmp;
 
           retval = TRUE;
           goto out;
index d05a8972de929444cda5c16b966db9a1f63546c0..51c209b5c66c6e2ead71f61e6c2b70286d6c1ac1 100644 (file)
@@ -186,6 +186,12 @@ test_search (void)
   check_found_backward ("This is some \303\240 text", "some \303\240", 0, 8, 14, "some \303\240");
   check_found_backward ("This is some \303\240 text", "\303\240 text", 0, 13, 19, "\303\240 text");
   check_found_backward ("This is some \303\240 text", "some \303\240 text", 0, 8, 19, "some \303\240 text");
+
+  /* multi-byte characters outside the needle */
+  check_found_forward ("\303\200 aa", "aa", 0, 2, 4, "aa");
+  check_found_forward ("aa \303\200", "aa", 0, 0, 2, "aa");
+  check_found_backward ("\303\200 aa", "aa", 0, 2, 4, "aa");
+  check_found_backward ("aa \303\200", "aa", 0, 0, 2, "aa");
 }
 
 static void
@@ -265,6 +271,12 @@ test_search_caseless (void)
   check_found_backward ("This is some Foo\nFoo text", "foo\nfoo", flags, 13, 20, "Foo\nFoo");
   check_found_backward ("This is some \303\200\n\303\200 text", "\303\240\n\303\240", flags, 13, 16, "\303\200\n\303\200");
   check_found_backward ("This is some \303\200\n\303\200 text", "a\314\200\na\314\200", flags, 13, 16, "\303\200\n\303\200");
+
+  /* multi-byte characters outside the needle */
+  check_found_forward ("\303\200 aa", "aa", flags, 2, 4, "aa");
+  check_found_forward ("aa \303\200", "aa", flags, 0, 2, "aa");
+  check_found_backward ("\303\200 aa", "aa", flags, 2, 4, "aa");
+  check_found_backward ("aa \303\200", "aa", flags, 0, 2, "aa");
 }
 
 static void